package com.jiankang.askhealth.util;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import java.util.TreeMap;

public class DateUtil extends org.apache.commons.lang.time.DateUtils {
    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DATE_FORMAT_DATE_TIME = "yyyy-MM-dd HH:mm";

    public static final long SECOND = 1000;
    public static final long JUST = SECOND * 5;
    public static final long MINUTE = SECOND * 60;
    public static final long HOUR = MINUTE * 60;
    public static final long DAY = HOUR * 24;
    public static final long WEEK = DAY * 7;
    public static final long MONTH = DAY * 30;
    public static final long YEAR = DAY * 365;

    public static final String[] zodiacArr = { "猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊" };
    public static final String[] constellationArr = { "水瓶座", "双鱼座", "牡羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座" };
    public static final int[] constellationEdgeDay = { 20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22 };

    /**
     * convert string(such as: 2003-11-26) to Date
     * @param dateStr string format of date
     * @return date
     */
    public static Date string2Date(String dateStr) {
        return string2Date(dateStr, DEFAULT_DATE_FORMAT);
    }

    /**
     * string to date, the format is same to SimpleDateFormat
     * for example "yyyyMMdd" "yyyy-MM-dd HH:mm" etc
     * please see java.text.SimpleDateFormat
     *
     * @param dateStr dateStr
     * @param format format
     * @return date
     */
    public static Date string2Date(String dateStr, String format) {
        if (dateStr==null || dateStr.length()==0) return null;
        DateFormat df = new SimpleDateFormat(format);
        try {
            return df.parse(dateStr);
        } catch (ParseException e) {
            //e.printStackTrace();
            return null;
        }
    }

    /**
     * convert date to string according to default format
     *
     * @param date date
     * @return string
     */
    public static String date2String(Date date) {
        return date2String(date, DEFAULT_DATE_FORMAT);
    }

    /**
     * convert date to string, and the format is same to SimpleDateFormat
     * for example "yyyyMMdd" "yyyy-MM-dd HH:mm" etc
     * please see java.text.SimpleDateFormat
     *
     * @param date date
     * @param format format
     * @return string
     */
    public static String date2String(Date date, String format) {
        if (date == null) {
            return "";
        }
        DateFormat df = new SimpleDateFormat(format);
        return df.format(date);
    }

    public static String getTimeDeltaStr(Date pastTime) {
        if (pastTime == null) {
            return "";
        }
        Date curTime = new Date();
        long delta = curTime.getTime() - pastTime.getTime();
        if (delta < MINUTE) {
            return (delta / SECOND) + "秒前";
        }
        else if (delta < HOUR) {
            return (delta / MINUTE) + "分前";
        }
        else if (delta < DAY) {
            return (delta / HOUR) + "小时前";
        }
        else if (delta < MONTH) {
            return (delta / DAY) + "天前";
        }
        else {
            return (delta / MONTH) + "个月前";
        }
    }

    public static String getTimeDelta2Str(Date pastTime) {
        if (pastTime == null) {
            return "";
        }
        Date curTime = new Date();
        long delta = curTime.getTime() - pastTime.getTime();
        if (delta < JUST) {
            return "刚刚";
        }
        else if (delta < MINUTE) {
            return (delta / SECOND) + "秒前";
        }
        else if (delta < HOUR) {
            return (delta / MINUTE) + "分前";
        }
        else if (delta < DAY) {
            return (delta / HOUR) + "小时前";
        }
        else if (delta < MONTH && delta < 4) {
            return (delta / DAY) + "天前";
        }
        else {
            return date2String(pastTime, "MM月dd日 HH:mm");
        }
    }

    public static String getExpiredTimeDeltaStr(Date expiredTime) {
        if (expiredTime == null) {
            return "";
        }
        Date curTime = new Date();
        long delta = expiredTime.getTime() - curTime.getTime();
        if (delta < MINUTE) {
            return (delta / SECOND) + "秒";
        }
        else if (delta < HOUR) {
            return (delta / MINUTE) + "分";
        }
        else if (delta < DAY) {
            return (delta / HOUR) + "小时";
        }
        else if (delta < MONTH) {
            return (delta / DAY) + "天";
        }
        else {
            return (delta / MONTH) + "个月";
        }
    }

    public static boolean isIn72Hr(Date lastTime) {
        boolean result = false;
        if (lastTime != null) {
            Date curTime = new Date();
            long delta = curTime.getTime() - lastTime.getTime();
            if (delta < DAY * 3) {
                result = true;
            }
        }
        return result;
    }

    public static boolean isIn24Hr(Date lastTime) {
        boolean result = false;
        if (lastTime != null) {
            Date curTime = new Date();
            long delta = curTime.getTime() - lastTime.getTime();
            if (delta < DAY) {
                result = true;
            }
        }
        return result;
    }

    public static boolean isIn12Hr(Date lastTime) {
        boolean result = false;
        if (lastTime != null) {
            Date curTime = new Date();
            long delta = curTime.getTime() - lastTime.getTime();
            if (delta < DAY / 2) {
                result = true;
            }
        }
        return result;
    }

    public static boolean isInNMin(Date lastTime, int n) {
        boolean result = false;
        if (lastTime != null) {
            Date curTime = new Date();
            long delta = curTime.getTime() - lastTime.getTime();
            if (delta < MINUTE * n) {
                result = true;
            }
        }
        return result;
    }

    public static boolean isIn3Sec(Date lastTime) {
        boolean result = false;
        if (lastTime != null) {
            Date curTime = new Date();
            long delta = curTime.getTime() - lastTime.getTime();
            if (delta < SECOND * 3) {
                result = true;
            }
        }
        return result;
    }

    public static Date getLastMinute() {
        return truncate(new Date((new Date()).getTime() - DateUtil.MINUTE), Calendar.MINUTE);
    }

    public static Date getLastMinute(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.MINUTE), Calendar.MINUTE);
    }

    public static Date getLastNMinute(int n) {
        return truncate(new Date((new Date()).getTime() - DateUtil.MINUTE * n), Calendar.MINUTE);
    }

    public static Date getLastNMinute(Date date, int n) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.MINUTE * n), Calendar.MINUTE);
    }

    public static Date getToday() {
        return truncate(new Date(), Calendar.DATE);
    }

    public static Date getYesterday() {
        return truncate(getYesterday(new Date()), Calendar.DATE);
    }

    public static Date getYesterday(Date today) {
        if (today == null) return null;
        return new Date(today.getTime() - DateUtil.DAY);
    }

    public static Date getDaysInPast(int numDay) {
        return truncate(new Date((new Date()).getTime() - DateUtil.DAY * numDay), Calendar.DATE);
    }

    public static Date getDaysInPast(Date date, int numDay) {
        return truncate(new Date(date.getTime() - DateUtil.DAY * numDay), Calendar.DATE);
    }

    public static Date getMonthsInPast(int numMonth) {
        return truncate(new Date((new Date()).getTime() - DateUtil.MONTH * numMonth), Calendar.DATE);
    }

    public static Date getMonthsInPast(Date date, int numMonth) {
        return truncate(new Date(date.getTime() - DateUtil.MONTH * numMonth), Calendar.DATE);
    }

    public static Date getTomorrow() {
        return truncate(new Date((new Date()).getTime() + DateUtil.DAY), Calendar.DATE);
    }

    public static Date getTomorrow(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() + DateUtil.DAY), Calendar.DATE);
    }

    public static Date getHoursInFuture(int numhour) {
        return truncate(new Date((new Date()).getTime() + DateUtil.HOUR * numhour), Calendar.MINUTE);
    }

    public static Date getDaysInFuture(int numDay) {
        return truncate(new Date((new Date()).getTime() + DateUtil.DAY * numDay), Calendar.DATE);
    }

    public static Date getDaysInFuture(Date date, int numDay) {
        return truncate(new Date(date.getTime() + DateUtil.DAY * numDay), Calendar.DATE);
    }

    public static Date getMonthsInFuture(int numMonth) {
        return truncate(new Date((new Date()).getTime() + DateUtil.MONTH * numMonth), Calendar.DATE);
    }

    public static Date getMonthsInFuture(Date date, int numMonth) {
        return truncate(new Date(date.getTime() + DateUtil.MONTH * numMonth), Calendar.DATE);
    }

    public static Date getLastWeek() {
        return truncate(new Date((new Date()).getTime() - DateUtil.WEEK), Calendar.DATE);
    }

    public static Date getLastWeek(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.WEEK), Calendar.DATE);
    }

    public static Date getLastTwoWeeks() {
        return truncate(new Date((new Date()).getTime() - DateUtil.WEEK * 2), Calendar.DATE);
    }

    public static Date getLastTwoWeeks(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.WEEK * 2), Calendar.DATE);
    }

    public static Date getNextWeek() {
        return truncate(new Date((new Date()).getTime() + DateUtil.WEEK), Calendar.DATE);
    }

    public static Date getNextWeek(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() + DateUtil.WEEK), Calendar.DATE);
    }

    public static Date getInTwoWeeks() {
        return truncate(new Date((new Date()).getTime() + DateUtil.WEEK * 2), Calendar.DATE);
    }

    public static Date getInTwoWeeks(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() + DateUtil.WEEK * 2), Calendar.DATE);
    }

    public static Date getLastMonth() {
        return truncate(new Date((new Date()).getTime() - DateUtil.MONTH), Calendar.DATE);
    }

    public static Date getLastMonth(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.MONTH), Calendar.DATE);
    }

    public static Date getLastNumMonth(int num) {
        return truncate(new Date((new Date()).getTime() - DateUtil.MONTH * num), Calendar.DATE);
    }

    public static Date getLastNumMonth(int num, Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.MONTH * num), Calendar.DATE);
    }

    public static Date getMonthFirstDay() {
        return truncate(new Date(), Calendar.MONTH);
    }

    public static Date getMonthFirstDay(Date date) {
        if (date == null) return null;
        return truncate(date, Calendar.MONTH);
    }

    public static Date getMonthFirstDayOfMonthsInPast(int numMonth) {
        return getMonthFirstDay(getMonthsInPast(getMonthLastDay(), numMonth));
    }

    public static Date getMonthLastDay() {
        return getYesterday(getMonthFirstDay(new Date(getMonthFirstDay().getTime() + DateUtil.DAY * 32)));
    }

    public static Date getMonthLastDay(Date date) {
        if (date == null) return null;
        return getYesterday(getMonthFirstDay(new Date(getMonthFirstDay(date).getTime() + DateUtil.DAY * 32)));
    }

    public static Date getMonthLastDayOfMonthsInFuture(int numMonth) {
        return getMonthLastDay(getMonthsInFuture(getMonthFirstDay(), numMonth));
    }

    public static Date getLastMonthFirstDay() {
        return getMonthFirstDay(getLastMonthLastDay());
    }

    public static Date getLastMonthFirstDay(Date date) {
        if (date == null) return null;
        return getMonthFirstDay(getLastMonthLastDay(date));
    }

    public static Date getLastMonthLastDay() {
        return getYesterday(getMonthFirstDay());
    }

    public static Date getLastMonthLastDay(Date date) {
        if (date == null) return null;
        return getYesterday(getMonthFirstDay(date));
    }

    public static Date getNextMonth() {
        return truncate(new Date((new Date()).getTime() + DateUtil.MONTH), Calendar.DATE);
    }

    public static Date getNextMonth(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() + DateUtil.MONTH), Calendar.DATE);
    }

    public static Date getNextMonthFirstDay(Date date){
        if (date == null) return null;
        return getTomorrow(getMonthLastDay(date));
    }

    public static Date getNextMonthLastDay(Date date){
        if (date == null) return null;
        return getMonthLastDay(getTomorrow(getMonthLastDay(date)));
    }

    public static Date getInTwoMonths() {
        return truncate(new Date((new Date()).getTime() + DateUtil.MONTH * 2), Calendar.DATE);
    }

    public static Date getInTwoMonths(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() + DateUtil.MONTH * 2), Calendar.DATE);
    }

    public static int getDiffInDays(Date start, Date end) {
        if (start == null || end == null) return 0;
        return Math.abs((int) ((end.getTime() - start.getTime()) / DAY));
    }

    public static int getSignedDiffInDays(Date start, Date end) {
        if (start == null || end == null) return 0;
        return (int) ((end.getTime() - start.getTime()) / DAY);
    }

    public static int getDiffInHours(Date start, Date end) {
        if (start == null || end == null) return 0;
        return Math.abs((int) ((end.getTime() - start.getTime()) / HOUR));
    }

    public static int getDiffInMinutes(Date start, Date end) {
        if (start == null || end == null) return 0;
        return Math.abs((int) ((end.getTime() - start.getTime()) / MINUTE));
    }

    public static int getDaysInMonth(Date date){
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(getMonthLastDay(date));
        return (calendar.get(Calendar.DAY_OF_MONTH));
    }

    public static Date getLastYear() {
        return truncate(new Date((new Date()).getTime() - DateUtil.YEAR), Calendar.DATE);
    }

    public static Date getLastYear(Date date) {
        if (date == null) return null;
        return truncate(new Date(date.getTime() - DateUtil.YEAR), Calendar.DATE);
    }

    public static Date getLastTwoYears() {
        return truncate(new Date((new Date()).getTime() - DateUtil.YEAR * 2), Calendar.DATE);
    }

    public static Date getLastThreeYears() {
        return truncate(new Date((new Date()).getTime() - DateUtil.YEAR * 3), Calendar.DATE);
    }

    public static boolean isWeekend() {
        return isWeekend(getToday());
    }

    public static boolean isWeekend(Date date) {
        int day = date.getDay();
        return (day == 0 || day == 6);
    }

    public static Map<Integer, Date> getMonthCalendar(Date date){
        if(date == null) return null;

        Map<Integer, Date> calendarMap = new TreeMap<Integer, Date>();
        Date currentDate = getMonthFirstDay(date);
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(currentDate);
        int begin = calendar.get(Calendar.DAY_OF_WEEK);
        if(begin == 1){ begin = 7; }
        else if(begin == 7){begin = 6; }
        else{begin = begin - 1;}
        
        int end = begin + DateUtil.getDiffInDays(currentDate, getMonthLastDay(date));
        
        for(Integer i = 1; i < begin; i++){
            calendarMap.put(i, null);
        }
        for(Integer i = begin; i <= 42; i++){
            if(calendarMap.size() >= end && (calendarMap.size() % 7 == 0)){
                break;
            }

            if(i == begin){
                calendarMap.put(i, currentDate);
            }
            else if(i <= end) {
                currentDate = DateUtil.getTomorrow(currentDate);
                calendarMap.put(i, currentDate);
            }
            else{
                calendarMap.put(i, null);
            }
        }
        return calendarMap;
    }

    public static Map<Integer, Date> getLastMonthCalendar(Date date){
        return getMonthCalendar(getYesterday(getMonthFirstDay(date)));    
    }

    public static Map<Integer, Date> getNextMonthCalendar(Date date){
        return getMonthCalendar(getTomorrow(getMonthLastDay(date)));
    }

    public static List<Date> getOneWeekDays(Date date){
        if(date == null) return null;
        List<Date> days = new ArrayList<Date>();
        Date currentDate = date;
        for(int i=1; i<= 7; i++){
            days.add(currentDate);
            currentDate = getTomorrow(currentDate);
        }
        return days;
    }

    public static boolean isHoliday(String dateStr) {
        return isHoliday(string2Date(dateStr));
    }
    
    public static Date getHolidayFirstDate(Date date) {
        if (date == null) return null;
        
        boolean result = false;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        Date begin, end;

        // 元旦 1 (01/01 ~ 01/02)
        calendar.set(Calendar.MONTH, Calendar.JANUARY);
        calendar.set(Calendar.DATE, 1);
        begin = calendar.getTime();
        end = getDaysInFuture(begin, 2);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 春节 (小年夜 ~ 初五)
        begin = getGregorianCalendar(calendar.get(Calendar.YEAR)-1+"-12-29");
        end = getDaysInFuture(begin, 7);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 清明 (04/02 ~ 04/06)
        calendar.set(Calendar.MONTH, Calendar.APRIL);
        calendar.set(Calendar.DATE, 2);
        begin = calendar.getTime();
        end = getDaysInFuture(begin, 5);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 劳动 (04/28 ~ 05/02)
        calendar.set(Calendar.MONTH, Calendar.APRIL);
        calendar.set(Calendar.DATE, 28);
        begin = calendar.getTime();
        end = getDaysInFuture(begin, 5);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 端午 (五月初二 ~ 初六)
        begin = getGregorianCalendar(calendar.get(Calendar.YEAR)+"-05-02");
        end = getDaysInFuture(begin, 5);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 中秋 (八月十二 ~ 十六)
        begin = getGregorianCalendar(calendar.get(Calendar.YEAR)+"-08-12");
        end = getDaysInFuture(begin, 5);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 国庆节 (09/28 ~ 10/06)
        calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);
        calendar.set(Calendar.DATE, 30);
        begin = calendar.getTime();
        end = getDaysInFuture(begin, 9);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;

        // 元旦 2 (12/29 ~ 12/31)
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DATE, 29);
        begin = calendar.getTime();
        end = getDaysInFuture(begin, 3);
        result = (date.compareTo(begin) >= 0 && date.compareTo(end) < 0);
        if (result) return begin;
        
        return null;
    }

    public static boolean isHoliday(Date date) {
        if (date==null) return false;
        
        boolean result = false;
        
        Date holidayFirstDate = getHolidayFirstDate(date);
        if (holidayFirstDate != null)
            result = true;

        return result;
    }

    public static boolean isOffPeakHours() {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        return (hour >= 0 && hour <= 7);
    }

    /* 根据年份获取年龄 */
    public static int year2Age(int year) {
        int age = 0;
        Calendar calendar = Calendar.getInstance();
        age = calendar.get(Calendar.YEAR) - year;
        return (age > 0) ? age : 0;
    }

    /* 根据年份获取年龄段 */
    public static int year2AgeGrp(int year) {
        return year % 100 / 10 * 10;
    }

    /* 根据年份获取生肖 */
    public static String year2Zodiac(int year) {
        return zodiacArr[year % 12];
    }

    /* 根据日期获取星座 */
    public static String date2Constellation(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        if (day < constellationEdgeDay[month]) {
            month = month - 1;
        }
        if (month >= 0) {
            return constellationArr[month];
        }else {
            return constellationArr[11];
        }
    }

    /* 阴阳历转换 */
    private final static int MONTH_DAYS[] = {29, 30};
    private final static int DAYS_MONTH[][] = {
            {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
            {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
    };
    private final static int DATAS[][] = {
            {23, 3, 2, 17, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0},
            {41, 0, 4, 23, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1},
            {30, 7, 5, 28, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1},
            {49, 0, 6, 33, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1},
            {38, 0, 0, 38, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},
            {26, 6, 2, 44, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0},
            {45, 0, 3, 49, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},
            {35, 0, 4, 54, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1},
            {24, 4, 5, 59, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1},
            {43, 0, 0, 5, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1},
            {32, 0, 1, 10, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1},
            {21, 2, 2, 15, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1},
            {40, 0, 3, 20, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1},
            {28, 7, 5, 26, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},
            {47, 0, 6, 31, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1},
            {36, 0, 0, 36, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},
            {26, 5, 1, 41, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1},
            {44, 0, 3, 47, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1},
            {33, 0, 4, 52, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0},
            {23, 3, 5, 57, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1},
            {42, 0, 6, 2, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1},
            {30, 8, 1, 8, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0},
            {48, 0, 2, 13, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0},
            {38, 0, 3, 18, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
            {27, 6, 4, 23, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0},
            {45, 0, 6, 29, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0},
            {35, 0, 0, 34, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1},
            {24, 4, 1, 39, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0},
            {43, 0, 2, 44, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0},
            {32, 0, 4, 50, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1},
            {20, 3, 5, 55, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0},
            {39, 0, 6, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0},
            {29, 7, 0, 5, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1},
            {47, 0, 2, 11, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1},
            {36, 0, 3, 16, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0},
            {26, 5, 4, 21, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1},
            {45, 0, 5, 26, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1},
            {33, 0, 0, 32, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1},
            {22, 4, 1, 37, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1},
            {41, 0, 2, 42, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1},
            {30, 8, 3, 47, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1},
            {48, 0, 5, 53, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1},
            {37, 0, 6, 58, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1},
            {27, 6, 0, 3, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0},
            {46, 0, 1, 8, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0},
            {35, 0, 3, 14, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1},
            {24, 4, 4, 19, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1},
            {43, 0, 5, 24, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1},
            {32, 10, 6, 29, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1},
            {50, 0, 1, 35, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0},
            {39, 0, 2, 40, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1},
            {28, 6, 3, 45, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0},
            {47, 0, 4, 50, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1},
            {36, 0, 6, 56, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0},
            {26, 5, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1},
            {45, 0, 1, 6, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0},
            {34, 0, 2, 11, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0},
            {22, 3, 4, 17, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0},
            {40, 0, 5, 22, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0},
            {30, 8, 6, 27, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1},
            {49, 0, 0, 32, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1},
            {37, 0, 2, 38, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1},
            {27, 5, 3, 43, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1},
            {46, 0, 4, 48, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1},
            {35, 0, 5, 53, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1},
            {23, 4, 0, 59, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},
            {42, 0, 1, 4, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},
            {31, 0, 2, 9, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0},
            {21, 2, 3, 14, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1},
            {39, 0, 5, 20, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1},
            {28, 7, 6, 25, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1},
            {48, 0, 0, 30, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1},
            {37, 0, 1, 35, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1},
            {25, 5, 3, 41, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1},
            {44, 0, 4, 46, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1},
            {33, 0, 5, 51, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},
            {22, 4, 6, 56, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},
            {40, 0, 1, 2, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0},
            {30, 9, 2, 7, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1},
            {49, 0, 3, 12, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1},
            {38, 0, 4, 17, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0},
            {27, 6, 6, 23, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1},
            {46, 0, 0, 28, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0},
            {35, 0, 1, 33, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0},
            {24, 4, 2, 38, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1},
            {42, 0, 4, 44, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1},
            {31, 0, 5, 49, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0},
            {21, 2, 6, 54, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1},
            {40, 0, 0, 59, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1},
            {28, 6, 2, 5, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0},
            {47, 0, 3, 10, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1},
            {36, 0, 4, 15, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1},
            {25, 5, 5, 20, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0},
            {43, 0, 0, 26, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1},
            {32, 0, 1, 31, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0},
            {22, 3, 2, 36, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0}
    };

    /**
     * 根据阴历取得对应的阳历日期（该日期必须在1936—2028年之间）
     *
     * @param date 阴历日期（字符串）
     * @return 返回对应的阳历日期
     * @throws Exception
     */
    public static Date getGregorianCalendar(String date) {
        Calendar c = _getCalendar(date);
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH) + 1;
        int day = c.get(Calendar.DAY_OF_MONTH);
        int index = year - 1936;
        int endIndex = month;

        if ((DATAS[index][1] != 0) && (month > DATAS[index][1])) {
            endIndex++;
        }

        int dayNum = 0;

        for (int i = 0; i < (endIndex - 1); i++) {
            dayNum += MONTH_DAYS[DATAS[index][4 + i]];
        }

        dayNum += day;
        dayNum += DATAS[index][0];

        int year_days = 365;

        if (_isLeapYear(year)) {
            year_days = 366;
        }

        if (dayNum > year_days) {
            year++;
            dayNum -= year_days;
        }

        month = 1;

        int dayOfMonth[] = DAYS_MONTH[0];

        if (_isLeapYear(year)) {
            dayOfMonth = DAYS_MONTH[1];
        }

        int i = 0;

        for (; i < 12; i++) {
            dayNum -= dayOfMonth[i];

            if (dayNum <= 0) {
                break;
            }

            month++;
        }

        day = dayOfMonth[i] + dayNum;

        return string2Date(year + "-" + month + "-" + day);
    }

    /**
     * 根据阳历取得对应的阴历日期（该日期必须在1936—2028年之间）
     *
     * @param date 阳历日期（字符串）
     * @return 返回阴历日期
     * @throws Exception
     */
    public static Date getLunarCalendar(String date) {
        Calendar calendar = _getCalendar(date);
        int year = calendar.get(Calendar.YEAR);
        int month = 1;
        int day;

        if ((year < 1936) || (year > 2028)) {
            return null;
        }

        int index = year - 1936;
        int l_days = DATAS[index][0];
        int day_year = calendar.get(Calendar.DAY_OF_YEAR);
        int days;

        if (day_year >= l_days) {
            days = day_year - l_days;
        } else {
            index--;
            year--;

            Calendar c = _getCalendar(year + "-12-31");
            days = (c.get((Calendar.DAY_OF_YEAR)) + day_year) -
                    DATAS[index][0];
        }

        int i = 0;
        int day_num = 0;

        for (; i < 13; i++) {
            day_num += MONTH_DAYS[DATAS[index][i + 4]];

            if (day_num >= days) {
                break;
            }

            month++;
        }

        day = MONTH_DAYS[DATAS[index][i + 4]] - (day_num - days);

        if ((DATAS[index][1] != 0) && (month > DATAS[index][1])) {
            month--;
        }

        return string2Date(year + "-" + month + "-" + day);
    }

    private static Calendar _getCalendar(String date) {
        Date dd = string2Date(date);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(dd);
        return calendar;
    }

    private static boolean _isLeapYear(int year) {
        if ((year % 400) == 0) {
            return true;
        } else if ((year % 100) == 0) {
            return false;
        } else if ((year % 4) == 0) {
            return true;
        }
        return false;
    }
    
    /**
     * 是否是紧急日期
     * 紧急日期定义:二天内（不包括当天）或是节假日范围
     * @param date
     * @return
     */
    public static boolean isUrgentDate(Date date) {
        Date today = DateUtil.getToday();
        int diffInDays = DateUtil.getDiffInDays(date, today);
        if (diffInDays < 3) {
            return true;
        }
        Date holidayFirstDate = getHolidayFirstDate(date);
        if (holidayFirstDate == null) {
            return false;
        } 
        diffInDays = DateUtil.getDiffInDays(holidayFirstDate, today);
        if (diffInDays < 8) {
            return true;
        }
        return false;
    }
    
    /**
     * 取得日期中的小时数
     * @param date
     * @return
     */
    public static int getHour(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        return hour;
    }
    
    public static int getMinute(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int minute = cal.get(Calendar.MINUTE);
        return minute;
    }
    
    /**
     * 判断日期是否为同年同月
     * @param date1
     * @param date2
     * @return
     */
    public static boolean isSameMonth(Date date1, Date date2) {
        String month1 = date2String(date1, "yyyy-MM");
        String month2 = date2String(date2, "yyyy-MM");
        if (month1.equals(month2)) {
            return true;
        }
        return false;
    }


    public static void main(String[] args) {
    }
}